<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Image Filters</title>
    <style>
        body {
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 5px;
            margin: 20px;
        }
        canvas {
            margin-top: 10px;
        }
    </style>
</head>
<body>
    <h1>Image Filters</h1>
    <input type="file" id="upload" accept="image/*">
    <select id="filters">
        <option value="grayscale">灰度滤镜</option>
        <option value="binarize">二值化</option>
        <option value="enhanced">亮度增强</option>
        <option value="blur">模糊</option>
        <option value="apply_sharpen">锐化</option>
        <option value="contour">轮廓滤镜</option>
        <option value="emboss">浮雕滤镜</option>
        <option value="detail">细节滤镜</option>
        <option value="edgeenhance">边缘增强滤镜</option>
        <option value="edgeenhancemore">更强边缘增强滤镜</option>
        <option value="smooth">平滑滤镜</option>
        <option value="smoothmore">更强平滑滤镜</option>
        <option value="bifilter">图像双边滤波处理(美颜)</option>
        <option value="nostalgia">怀旧滤镜</option>
        <option value="liulian">流年滤镜</option>
        <option value="lighting">光照滤镜</option>
        <option value="tuTouJing">凸透镜滤镜</option>
        <option value="sumiao">素描滤镜</option>
        <option value="quancai">全彩</option>
        <option value="qianbihua">铅笔画滤镜</option>
        <option value="bianjie">只保留边界滤镜</option>
        <option value="fanse">反色滤镜</option>
        <option value="stylization">图像水彩画效果处理</option>
        <option value="katong">卡通滤镜</option>
        <option value="dianying">摄影效果滤镜</option>
    </select>
    <button onclick="applyFilter()">Apply Filter</button>

    <span id="filter-text"></span>
    <canvas id="canvas"></canvas>

    <script>
        const canvas = document.getElementById('canvas');
        const ctx = canvas.getContext('2d');
        let originalImage = null;

        document.getElementById('upload').addEventListener('change', (event) => {
            const file = event.target.files[0];
            if (file) {
                const reader = new FileReader();
                reader.onload = function(e) {
                    const img = new Image();
                    img.onload = function() {
                        canvas.width = img.width;
                        canvas.height = img.height;
                        ctx.drawImage(img, 0, 0);
                        originalImage = ctx.getImageData(0, 0, canvas.width, canvas.height);
                    }
                    img.src = e.target.result;
                }
                reader.readAsDataURL(file);
            }
        });

        function applyFilter() {
            if (!originalImage) return;
            const filter = document.getElementById('filters').value;

            document.getElementById('filter-text').innerText = filter;

            ctx.putImageData(originalImage, 0, 0);

            switch (filter) {
                case 'grayscale':
                    grayscale();
                    break;
                case 'binarize':
                    binarize();
                    break;
                case 'enhanced':
                    enhanced();
                    break;
                case 'blur':
                    blur();
                    break;
                case 'apply_sharpen':
                    applySharpen();
                    break;
                case 'contour':
                    contour();
                    break;
                case 'emboss':
                    emboss();
                    break;
                case 'detail':
                    detail();
                    break;
                case 'edgeenhance':
                    edgeEnhance();
                    break;
                case 'edgeenhancemore':
                    edgeEnhanceMore();
                    break;
                case 'smooth':
                    smooth();
                    break;
                case 'smoothmore':
                    smoothMore();
                    break;
                case 'bifilter':
                    bifilter();
                    break;
                case 'nostalgia':
                    nostalgia();
                    break;
                case 'liulian':
                    liulian();
                    break;
                case 'lighting':
                    lighting();
                    break;
                case 'tuTouJing':
                    tuTouJing();
                    break;
                case 'sumiao':
                    sumiao();
                    break;
                case 'quancai':
                    quancai();
                    break;
                case 'qianbihua':
                    qianbihua();
                    break;
                case 'bianjie':
                    bianjie();
                    break;
                case 'fanse':
                    fanse();
                    break;
                case 'stylization':
                    stylization();
                    break;
                case 'katong':
                    katong();
                    break;
                case 'dianying':
                    dianying();
                    break;
                default:
                    break;
            }
        }

        function grayscale() {
            const imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);
            const data = imgData.data;
            for (let i = 0; i < data.length; i += 4) {
                const gray = 0.299 * data[i] + 0.587 * data[i + 1] + 0.114 * data[i + 2];
                data[i] = data[i + 1] = data[i + 2] = gray;
            }
            ctx.putImageData(imgData, 0, 0);
        }

        function binarize(threshold = 128) {
            const imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);
            const data = imgData.data;
            for (let i = 0; i < data.length; i += 4) {
                const gray = 0.299 * data[i] + 0.587 * data[i + 1] + 0.114 * data[i + 2];
                const value = gray < threshold ? 0 : 255;
                data[i] = data[i + 1] = data[i + 2] = value;
            }
            ctx.putImageData(imgData, 0, 0);
        }

        function enhanced() {
            const imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);
            const data = imgData.data;
            for (let i = 0; i < data.length; i++) {
                data[i] = Math.min(255, data[i] * 1.2);
            }
            ctx.putImageData(imgData, 0, 0);
        }

        function blur(radius = 2) {
            // Gaussian blur logic can be implemented here, for simplicity we use CSS filter
            ctx.filter = `blur(${radius}px)`;
            ctx.drawImage(canvas, 0, 0);
            ctx.filter = 'none';
        }

        function applySharpen() {
            const imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);
            const data = imgData.data;
            const w = imgData.width;
            const h = imgData.height;
            const kernel = [
                0, -1, 0,
                -1, 5, -1,
                0, -1, 0
            ];
            const side = Math.round(Math.sqrt(kernel.length));
            const halfSide = Math.floor(side / 2);

            const output = ctx.createImageData(w, h);
            const dst = output.data;

            for (let y = 0; y < h; y++) {
                for (let x = 0; x < w; x++) {
                    const sy = y;
                    const sx = x;
                    const dstOff = (y * w + x) * 4;
                    let r = 0, g = 0, b = 0;
                    for (let cy = 0; cy < side; cy++) {
                        for (let cx = 0; cx < side; cx++) {
                            const scy = sy + cy - halfSide;
                            const scx = sx + cx - halfSide;
                            if (scy >= 0 && scy < h && scx >= 0 && scx < w) {
                                const srcOff = (scy * w + scx) * 4;
                                const wt = kernel[cy * side + cx];
                                r += data[srcOff] * wt;
                                g += data[srcOff + 1] * wt;
                                b += data[srcOff + 2] * wt;
                            }
                        }
                    }
                    dst[dstOff] = r;
                    dst[dstOff + 1] = g;
                    dst[dstOff + 2] = b;
                    dst[dstOff + 3] = data[dstOff + 3];
                }
            }
            ctx.putImageData(output, 0, 0);
        }

        function contour() {
            ctx.filter = 'contrast(0.8) brightness(1.2)';
            ctx.drawImage(canvas, 0, 0);
            ctx.filter = 'none';
        }

        function emboss() {
            const imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);
            const data = imgData.data;
            const width = imgData.width;
            const height = imgData.height;
            const output = new Uint8ClampedArray(data);

            for (let i = 0; i < height; i++) {
                for (let j = 0; j < width; j++) {
                    const idx = (i * width + j) * 4;
                    const nextIdx = ((i + 1) * width + (j + 1)) * 4;
                    if (nextIdx < data.length) {
                        for (let k = 0; k < 3; k++) {
                            output[idx + k] = 128 + data[idx + k] - data[nextIdx + k];
                        }
                    }
                }
            }

            for (let i = 0; i < data.length; i++) {
                imgData.data[i] = output[i];
            }

            ctx.putImageData(imgData, 0, 0);
        }

        function detail() {
            ctx.filter = 'contrast(1.2) brightness(1.1)';
            ctx.drawImage(canvas, 0, 0);
            ctx.filter = 'none';
        }

        function edgeEnhance() {
            ctx.filter = 'contrast(1.3) brightness(1.2)';
            ctx.drawImage(canvas, 0, 0);
            ctx.filter = 'none';
        }

        function edgeEnhanceMore() {
            ctx.filter = 'contrast(1.5) brightness(1.3)';
            ctx.drawImage(canvas, 0, 0);
            ctx.filter = 'none';
        }

        function smooth() {
            ctx.filter = 'blur(1px)';
            ctx.drawImage(canvas, 0, 0);
            ctx.filter = 'none';
        }

        function smoothMore() {
            ctx.filter = 'blur(2px)';
            ctx.drawImage(canvas, 0, 0);
            ctx.filter = 'none';
        }

        function bifilter() {
            // Bilateral filter logic can be implemented here
        }

        function nostalgia() {
            const imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);
            const data = imgData.data;
            for (let i = 0; i < data.length; i += 4) {
                const tr = 0.393 * data[i] + 0.769 * data[i + 1] + 0.189 * data[i + 2];
                const tg = 0.349 * data[i] + 0.686 * data[i + 1] + 0.168 * data[i + 2];
                const tb = 0.272 * data[i] + 0.534 * data[i + 1] + 0.131 * data[i + 2];
                data[i] = Math.min(255, tr);
                data[i + 1] = Math.min(255, tg);
                data[i + 2] = Math.min(255, tb);
            }
            ctx.putImageData(imgData, 0, 0);
        }

        function liulian() {
            const imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);
            const data = imgData.data;

            for (let i = 0; i < imgData.height; i++) {
                for (let j = 0; j < imgData.width; j++) {
                    const idx = (i * imgData.width + j) * 4;
                    const B = Math.min(255, Math.sqrt(data[idx]) * 12);
                    const G = data[idx + 1];
                    const R = data[idx + 2];
                    
                    data[idx] = B;
                    data[idx + 1] = G;
                    data[idx + 2] = R;
                }
            }

            ctx.putImageData(imgData, 0, 0);
        }

        function lighting() {
            const imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);
            const data = imgData.data;
            const width = imgData.width;
            const height = imgData.height;

            const centerX = width / 2;
            const centerY = height / 2;
            const radius = Math.min(centerX, centerY);
            const strength = 150;  // 光照强度

            for (let i = 0; i < height; i++) {
                for (let j = 0; j < width; j++) {
                    const idx = (i * width + j) * 4;
                    const distance = Math.sqrt(Math.pow(centerY - j, 2) + Math.pow(centerX - i, 2));

                    if (distance < radius) {
                        const result = Math.floor(strength * (1 - distance / radius));
                        data[idx] = Math.min(255, data[idx] + result);     // B通道
                        data[idx + 1] = Math.min(255, data[idx + 1] + result); // G通道
                        data[idx + 2] = Math.min(255, data[idx + 2] + result); // R通道
                    }
                }
            }

            ctx.putImageData(imgData, 0, 0);
        }

        function tuTouJing() {
            const imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);
            const data = imgData.data;
            const width = imgData.width;
            const height = imgData.height;
            const canvasData = new Uint8ClampedArray(data);

            const centerX = Math.floor(height / 2);
            const centerY = Math.floor(width / 2);
            const radius = Math.min(centerX, centerY);

            for (let i = 0; i < height; i++) {
                for (let j = 0; j < width; j++) {
                    const idx = (i * width + j) * 4;
                    const distance = Math.sqrt(Math.pow(i - centerX, 2) + Math.pow(j - centerY, 2));

                    if (distance <= radius) {
                        const k = 1 - Math.pow(distance / radius, 2);
                        const newI = Math.floor(i + k * (i - centerX));
                        const newJ = Math.floor(j + k * (j - centerY));

                        const newIClamped = Math.max(0, Math.min(newI, height - 1));
                        const newJClamped = Math.max(0, Math.min(newJ, width - 1));

                        const newIdx = (newIClamped * width + newJClamped) * 4;
                        canvasData[idx] = data[newIdx];
                        canvasData[idx + 1] = data[newIdx + 1];
                        canvasData[idx + 2] = data[newIdx + 2];
                        canvasData[idx + 3] = data[newIdx + 3];
                    } else {
                        canvasData[idx] = data[idx];
                        canvasData[idx + 1] = data[idx + 1];
                        canvasData[idx + 2] = data[idx + 2];
                        canvasData[idx + 3] = data[idx + 3];
                    }
                }
            }

            ctx.putImageData(new ImageData(canvasData, width, height), 0, 0);
        }

        function sumiao() {
            // Implement Sketch filter logic here
        }

        function quancai() {
            // Implement Full Color filter logic here
        }

        function qianbihua() {
            ctx.filter = 'contrast(0.8) brightness(1.2)';
            ctx.drawImage(canvas, 0, 0);
            ctx.filter = 'none';
        }

        function bianjie() {
            ctx.filter = 'contrast(1.2) brightness(0.7)';
            ctx.drawImage(canvas, 0, 0);
            ctx.filter = 'none';
        }

        function fanse() {
            const imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);
            const data = imgData.data;
            for (let i = 0; i < data.length; i += 4) {
                data[i] = 255 - data[i];
                data[i + 1] = 255 - data[i + 1];
                data[i + 2] = 255 - data[i + 2];
            }
            ctx.putImageData(imgData, 0, 0);
        }

        function stylization() {
            // Implement Watercolor filter logic here
        }

        function katong() {
            // Implement Cartoon filter logic here
        }

        function dianying() {
            // Implement Vignette filter logic here
        }
    </script>
</body>
</html>
